package com.tvunetworks.center.device.service.impl;

import com.tvunetworks.center.common.constant.LocalConstant;
import com.tvunetworks.center.common.exception.ServerException;
import com.tvunetworks.center.common.model.LoginUser;
import com.tvunetworks.center.common.model.param.GetIdleChannelParam;
import com.tvunetworks.center.common.util.Result;
import com.tvunetworks.center.common.util.ResultUtil;
import com.tvunetworks.center.device.model.param.CustomizedLiveParam;
import com.tvunetworks.center.device.model.result.ResultConstant;
import com.tvunetworks.center.device.service.*;
import com.tvunetworks.center.device.service.feign.CustomizedUserFeignService;
import com.tvunetworks.center.device.service.feign.TokenFeignService;
import com.tvunetworks.center.device.service.feign.UserFeignService;
import com.tvunetworks.center.gs.model.Device;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @program: tvucc-aggregator
 * @description: CustomizedLiveServiceImpl
 * @author lebronchen
 * @create: 2020-03-17 16:05
 **/
@Service
@Slf4j
public class CustomizedLiveServiceImpl implements CustomizedLiveService {

    @Autowired
    private ReceiverControlService receiverControlService;
    @Autowired
    private DeviceExtraService deviceExtraService;
    @Autowired
    private CustomizedShareService customizedShareService;
    @Autowired
    private CustomizedShareRecordService customizedShareRecordService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private UserFeignService userFeignService;
    @Autowired
    private DevicePairService devicePairService;
    @Autowired
    private TokenFeignService tokenFeignService;
    @Autowired
    private CustomizedUserFeignService customizedUserFeignService;

    @Value("${customized.liveFilterGroup}")
    private boolean liveFilterGroup;
    @Value("${customized.liveFilterPair}")
    private boolean liveFilterPair;
    @Value("${showAutoROnManualChannel}")
    private boolean showAutoROnManualChannel;
    @Value("${enableAutoShareFixedAddress}")
    private boolean enableAutoShareFixedAddress;

    @Override
    public void manualStartLive(LoginUser loginUser, CustomizedLiveParam param) {
        this.startLive(true, loginUser.getId(), loginUser.getRole(), param.getRid(), param.getSid());
    }

    @Override
    public String autoStartLive(LoginUser loginUser, CustomizedLiveParam param) {
        String userId = loginUser.getId();
        String sid = param.getSid();
        // 判断 Group 是否存在，并且把 GroupName 作为参数去获取一个自动 R
        String groupName = customizedUserFeignService.getGroupNameByUserDevice(userId, sid);
//        if (StringUtils.isBlank(groupName)) {
//            ServerException.Exception(ResultConstant.Group.NOT_EXIST);
//        }
        GetIdleChannelParam idleChannelParam = new GetIdleChannelParam()
                .setBooking(false)
                .setUserId(userId)
                .setGroupName(groupName)
                .setSid(sid);
        Device channel = this.getIdleChannel(idleChannelParam);
        if (channel == null) {
            // 没有可用的 R
            ServerException.Exception(ResultConstant.Customized.AutoDevice.NO_IDLE_CHANNEL);
        }
        param.setRid(channel.getPeerId());
        this.startLive(false, userId, loginUser.getRole(), param.getRid(), sid);
        return channel.getPeerId();
    }



    private void startLive(boolean manual, String userId, String userRole, String rid, String sid) {
        // 校验 R 自动/手动 是否匹配
        if (!showAutoROnManualChannel) {
            boolean deviceManual = deviceExtraService.isDeviceManual(rid);
            if (manual != deviceManual) {
                if (manual) {
                    ServerException.Exception(ResultConstant.Customized.Live.R_NOT_MANUAL);
                } else {
                    ServerException.Exception(ResultConstant.Customized.Live.R_NOT_AUTO);
                }
            }
        }

        // 调用 R 接口开启直播
        Result<String> result = receiverControlService.startLive(userId, userRole, rid, sid);
        if (!result.assertSuccess()) {
            ServerException.Exception(result);
        }

        // 等待 R 状态切换到 living 再去调用推流
        waitRLiveStatus(rid, 2000);

        if (enableAutoShareFixedAddress) {
            // 自动推流到固定的地址
            customizedShareService.tAutoShareFixedAddress(userId, rid, sid);
        }

        // 根据上次 stopLive 时保留的推流地址进行推流
        Set<String> needShareIds = customizedShareRecordService.clearAndListStartLiveNeedAutoShareIds(userId, sid);
        if (CollectionUtils.isEmpty(needShareIds)) {
            log.error("startLive needShareIds is null userId:{} rid:{} sid:{} manual:{}", userId, rid, sid, manual);
            return;
        }

        for (String shareId : needShareIds) {
            log.error("startLive auto startShare userId:{} rid:{} sid:{} shareId:{}", userId, rid, sid, shareId);
            customizedShareService.startShare(userId, rid, shareId);
        }

    }

    @Override
    public void stopLive(LoginUser loginUser, CustomizedLiveParam param) {
        // 调用 R 接口关闭直播
        Result<String> result = receiverControlService.stopLive(loginUser.getId(), loginUser.getRole(), param.getRid());
        if (!result.assertSuccess()) {
            ServerException.Exception(result);
        }

        // 关闭直播同时，停止所有推流
        customizedShareService.stopAllShare(loginUser.getId(), param.getRid(), param.getSid());
    }

    @Override
    public Device getIdleChannel(GetIdleChannelParam param) {
        String userId = param.getUserId();
        String groupName = param.getGroupName();
        if (StringUtils.isBlank(userId) && StringUtils.isBlank(groupName)) {
            // 参数错误
            ServerException.Exception(ResultUtil.paramErrorInfo());
        }

        List<String> list = new ArrayList<>();

        List<String> userRids = new ArrayList<>(0);
        if (StringUtils.isNotBlank(userId)) {
            // 查询出用户所有的 R
            userRids = userFeignService.listUserRids(userId);
            if (userRids == null) {
                userRids = new ArrayList<>();
            }
        }
        List<String> groupRids = new ArrayList<>(0);
        if (StringUtils.isNotBlank(groupName)) {
            // 查询 group 中的所有 R
            groupRids = customizedUserFeignService.listGroupRids(groupName);
            if (groupRids == null) {
                groupRids = new ArrayList<>();
            }
        }

        if (StringUtils.isBlank(userId)) {
            if (StringUtils.isBlank(groupName)) {
                // userId 和 groupName 都为空 参数错误
                ServerException.Exception(ResultUtil.paramErrorInfo());
            } else {
                // userId 为空，groupName 不为空，使用 groupRids
                list = groupRids;
            }
        } else {
            if (StringUtils.isBlank(groupName)) {
                // userId 不为空，groupName 为空，使用 userRids
                list = userRids;
            } else {
                // userId 和 groupName 都不为空 使用交集
                userRids.retainAll(groupRids);
                list = userRids;
            }
        }

        if (CollectionUtils.isEmpty(list)) {
            log.error("getAnAutoR no idle R, listUserRids null userId:{}", userId);
            ServerException.Exception(ResultConstant.Customized.IdleChannel.USER_OR_GROUP_NOT_BIND_R);
        }

        // 查询并过滤出用户所有的 自动 R
        this.getIdleChannelFilterAutoR(list);

        if (CollectionUtils.isEmpty(list)) {
            log.error("getAnAutoR no idle R, list.retainAll(autoDeviceIds) null userId:{}", userId);
            ServerException.Exception(ResultConstant.Customized.IdleChannel.USER_NO_AUTO_R);
        }

        // 查询并过滤参数中 Source 配对的 R
        String sid = param.getSid();
        if (StringUtils.isNotBlank(sid)) {
            this.getIdleChannelFilterPairR(sid, list);
            if (CollectionUtils.isEmpty(list)) {
                log.error("getAnAutoR no idle R, list.retainAll(autoDeviceIds) null userId:{}", userId);
                ServerException.Exception(ResultConstant.Customized.IdleChannel.USER_NO_AUTO_R);
            }
        }

        if (param.isBooking()) {
            // Booking 任务，要查询 任务期间没有被其他任务占用的 R
            if (CollectionUtils.isNotEmpty(param.getExistBookingRs())) {
                list.removeAll(param.getExistBookingRs());
            }
        } else {
            // 非 Booking 任务，要查询当前 online 的 R 查询并过滤参数中 online 的 R
            this.getIdleChannelFilterOnlineR(list);
            if (CollectionUtils.isEmpty(list)) {
                ServerException.Exception(ResultConstant.Customized.IdleChannel.NOT_EXIST_ONLINE_R);
            }
        }

        if (CollectionUtils.isEmpty(list)) {
            log.error("getAnAutoR after check booking, list null userId:{}", userId);
            ServerException.Exception(ResultConstant.Customized.IdleChannel.USER_NO_AUTO_R);
        }

        String rid = list.get((int) (Math.random() * list.size()));
        Device r = deviceService.getCurrentDevice(rid);
        return r;
    }

    @Override
    public boolean isChannelIdle(String userId, String rid) {
        List<String> autoDeviceIds = deviceExtraService.listCacheAutoPeerIds();
        if (CollectionUtils.isEmpty(autoDeviceIds)) {
            return false;
        }
        List<String> userRids = userFeignService.listUserRids(userId);
        if (CollectionUtils.isEmpty(userRids)) {
            return false;
        }
        autoDeviceIds.retainAll(userRids);
        if (CollectionUtils.isEmpty(autoDeviceIds)) {
            return false;
        }
        if (!autoDeviceIds.contains(rid)) {
            return false;
        }
        Device device = deviceService.getCurrentDevice(rid);
        if (device == null) {
            return false;
        }
        if (!LocalConstant.DeviceStatus.ONLINE.equals(device.getStatus())) {
            return false;
        }
        return true;
    }


    /**
     * 查询并过滤出用户所有的 自动 R
     * @param list
     */
    private void getIdleChannelFilterAutoR(List<String> list){
        List<String> autoDeviceIds = deviceExtraService.listCacheAutoPeerIds();
        if (CollectionUtils.isEmpty(autoDeviceIds)) {
            log.error("getAnAutoR no idle R, listCacheAutoPeerIds null");
            ServerException.Exception(ResultConstant.Customized.IdleChannel.GLOBAL_NO_AUTO_R);
        }
        list.retainAll(autoDeviceIds);

    }

    /**
     * 查询并过滤参数中 Source 配对的 R
     * @param sid
     * @param list
     */
    private void getIdleChannelFilterPairR(String sid, List<String> list){
        if (!liveFilterPair) {
            return;
        }
        Device source = deviceService.getCurrentDevice(sid);
        if (source == null) {
            ServerException.Exception(ResultConstant.Customized.IdleChannel.SOURCE_NOT_EXIST);
        }
        String type = source.getType();
        Set<String> pairedList = new HashSet<>();
        if (LocalConstant.DeviceType.T.equals(type)) {
            // 查询 TPDS 配对的 R
            List<String> tpdsRids = devicePairService.listTPairR(sid);
            if (!CollectionUtils.isEmpty(tpdsRids)) {
                pairedList.addAll(tpdsRids);
            }
            // 查询 Token 配对的 R
            Set<String> tokenRids = tokenFeignService.listTokenTPairedR(sid);
            if (!CollectionUtils.isEmpty(tokenRids)) {
                pairedList.addAll(tokenRids);
            }
        } else if (LocalConstant.DeviceType.X.equals(type)) {
            try {
                // 查询 GCS 配对的 R
                List<String> pairedRids = devicePairService.listXPairR(sid);
                if (!CollectionUtils.isEmpty(pairedRids)) {
                    pairedList.addAll(pairedRids);
                }
            } catch (IOException e) {
                log.error(e.toString(), e);
            }
        } else {
            return;
        }
        list.retainAll(pairedList);
    }

    /**
     * 查询并过滤参数中 online 的 R
     * @param list
     */
    private void getIdleChannelFilterOnlineR (List<String> list) {
        List<Device> devices = deviceService.listCurrentDevice(list);
        if (CollectionUtils.isEmpty(devices)) {
            ServerException.Exception(ResultConstant.Customized.IdleChannel.ALL_R_NOT_EXIST);
        }
        devices = devices.stream().filter(device -> LocalConstant.DeviceStatus.ONLINE.equals(device.getStatus())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(devices)) {
            ServerException.Exception(ResultConstant.Customized.IdleChannel.NOT_EXIST_ONLINE_R);
        }
        List<String> onlines = devices.stream().map(Device::getPeerId).collect(Collectors.toList());
        list.retainAll(onlines);
    }


    private String getAnAutoR(String userId){
        List<String> userRids = userFeignService.listUserRids(userId);
        if (CollectionUtils.isEmpty(userRids)) {
            log.error("getAnAutoR no idle R, listUserRids null userId:{}", userId);
            return null;
        }
        List<String> autoDeviceIds = deviceExtraService.listCacheAutoPeerIds();
        if (CollectionUtils.isEmpty(autoDeviceIds)) {
            log.error("getAnAutoR no idle R, listCacheAutoPeerIds null userId:{}", userId);
            return null;
        }
        userRids.retainAll(autoDeviceIds);
        if (CollectionUtils.isEmpty(userRids)) {
            log.error("getAnAutoR no idle R, userRids.retainAll(autoDeviceIds) null userId:{}", userId);
            return null;
        }
        List<Device> devices = deviceService.listCurrentDevice(userRids);
        if (CollectionUtils.isEmpty(devices)) {
            log.error("getAnAutoR no idle R, listCurrentDevice null userId:{} userRids:{}", userId, userRids);
            return null;
        }
        devices = devices.stream().filter(device -> LocalConstant.DeviceStatus.ONLINE.equals(device.getStatus())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(devices)) {
            log.error("getAnAutoR no idle R, filter online null userId:{} userRids:{}", userId, userRids);
            return null;
        }
        if (devices.size() == 1) {
            return devices.get(0).getPeerId();
        }
        return devices.get((int)(Math.random() * devices.size())).getPeerId();
    }

    /**
     * 等待 R 状态切换到 living
     * @param rid
     * @param timeout
     */
    private void waitRLiveStatus(String rid, long timeout) {
        if (StringUtils.isEmpty(rid)) {
            return;
        }
        Device device = deviceService.getCurrentDevice(rid);
        if (device == null) {
            return;
        }
        long start = System.currentTimeMillis();
        while (!LocalConstant.DeviceStatus.LIVING.equals(device.getStatus())) {
            long now = System.currentTimeMillis();
            if (now - start > timeout) {
                return;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                log.error(e.toString(), e);
            }
            device = deviceService.getCurrentDevice(rid);
        }
    }


}
